package com.labofjet.util;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 注解工具类
 * 
 * @author jyzjyz12@163.com
 * 
 */
public class AnnotationUtils {
    private static final Map<Class<?>, Map<Class<? extends Annotation>, List<Field>>> FIELD_CACHE = new ConcurrentHashMap<Class<?>, Map<Class<? extends Annotation>, List<Field>>>();
    private static final Map<Class<?>, Map<Class<? extends Annotation>, List<Method>>> METHOD_CACHE = new ConcurrentHashMap<Class<?>, Map<Class<? extends Annotation>, List<Method>>>();

    private AnnotationUtils() {

    }

    /**
     * 返回当前类上的注解,包括继承下来的,用的比较多
     * @param targetClass
     * @return
     */
    public static List<Annotation> getAnnotationInClass(Class<?> targetClass){
        return Arrays.asList(targetClass.getAnnotations());
    }
    
    /**
     * 返回当前类以及父类上的注解,去掉重复的,可能没啥用
     * @param targetClass
     * @return
     */
    public static List<Annotation> getAnnotationInClassAndSuperClass(Class<?> targetClass){
        List<Annotation> result = new ArrayList<Annotation>();
        result.addAll(getAnnotationInClass(targetClass));
        while (targetClass.getSuperclass() != null && targetClass.getSuperclass() != Object.class) {
            targetClass = targetClass.getSuperclass();
            result.addAll(getAnnotationInClass(targetClass));
        }
        result = new ArrayList<Annotation>(new HashSet<Annotation>(result));//去重
        return result;
    }
    
    /**
     * 查找当前类以及父类中含有给定注解的Field,有缓存
     * 
     * @param targetClass
     * @param annotation
     * @return
     */
    public static List<Field> getFieldInClassAndSuperClassByAnnotation(Class<?> targetClass, Class<? extends Annotation> annotation) {
        if (FIELD_CACHE.get(targetClass) != null && FIELD_CACHE.get(targetClass).get(annotation) != null) {//有缓存
            return FIELD_CACHE.get(targetClass).get(annotation);
        } else {//无缓存
            List<Field> resultList = new ArrayList<Field>();
            Map<Class<? extends Annotation>, List<Field>> map = new HashMap<Class<? extends Annotation>, List<Field>>();
            getAnnotationFieldInClassAndSuperClass(resultList, annotation, targetClass);
            map.put(annotation, resultList);
            FIELD_CACHE.put(targetClass, map);
            return resultList;
        }
    }

    /**
     * 查找当前类以及父类中含有给定注解的Method,有缓存
     * 
     * @param targetClass
     * @param annotation
     * @return
     */
    public static List<Method> getMethodInClassAndSuperClassByAnnotation(Class<?> targetClass, Class<? extends Annotation> annotation) {
        if (METHOD_CACHE.get(targetClass) != null && METHOD_CACHE.get(targetClass).get(annotation) != null) {//有缓存
            return METHOD_CACHE.get(targetClass).get(annotation);
        } else {//无缓存
            List<Method> resultList = new ArrayList<Method>();
            Map<Class<? extends Annotation>, List<Method>> map = new HashMap<Class<? extends Annotation>, List<Method>>();
            getAnnotationMethodInClassAndSuperClass(resultList, annotation, targetClass);
            map.put(annotation, resultList);
            METHOD_CACHE.put(targetClass, map);
            return resultList;
        }
    }

    private static void getAnnotationFieldInClassAndSuperClass(List<Field> resultList, Class<? extends Annotation> annotation,
            Class<?> targetClass) {
        //查找本类中的所有Field
        for (Field field : targetClass.getDeclaredFields()) {
            if (field.isAnnotationPresent(annotation)) {
                resultList.add(field);
            }
        }
        //递归查找父类中的所有Field
        if (targetClass.getSuperclass() != null && targetClass.getSuperclass() != Object.class) {
            getAnnotationFieldInClassAndSuperClass(resultList, annotation, targetClass.getSuperclass());
        }
    }

    private static void getAnnotationMethodInClassAndSuperClass(List<Method> resultList, Class<? extends Annotation> annotation,
            Class<?> targetClass) {
        //查找本类中的所有method
        for (Method method : targetClass.getDeclaredMethods()) {
            if (method.isAnnotationPresent(annotation)) {
                resultList.add(method);
            }
        }
        //递归查找父类中的所有method
        if (targetClass.getSuperclass() != null && targetClass.getSuperclass() != Object.class) {
            getAnnotationMethodInClassAndSuperClass(resultList, annotation, targetClass.getSuperclass());
        }
    }
}
